import json
from datetime import datetime
from hmac import digest

# 加密获取的通过&符号拼接成的字符串
from Crypto.PublicKey import RSA
from Crypto.Signature import PKCS1_v1_5
from Crypto.Hash import SHA256
from base64 import decodebytes,encodebytes
# 转义字符转化模块
from urllib.parse import quote_plus,urlparse,parse_qs
from django.shortcuts import render,redirect
from django_redis import get_redis_connection
from utils.encrypt import uid
from web import models

"""
    order_id = 2088721061481408
    params = {
        'app_id' : 2021000146632363,
        'method':'alipy.trade.page.pay',
        'format':'JSON',
        'return_url':'http://172.16.9.237:8007/web/price/', #支付成功之后跳转到指定的网址 
        'notify_url':"http://172.16.9.237:8007/web/price/",
        'charset':'utf-8',
        'sign_type':'RSA2',
        # 'sign':'签名',
        'timestamp':datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
        'version':'1.0',
        'biz_content':json.dumps({
            'out_trade_no': order_id,
            'product_code': 'FAST_INSTANT_TRADE_PAY',
            'total_amount': 11.68,
            'subject': '订单标题'
        },separators=(',',':'))
    }
    unsigned_string = '&'.join(['{0}={1}'.format(k,params[k]) for k in sorted(params)])
    
    # 对上面代签名的字符串进行加密签名
    private_key = RSA.importKey(open("files/skd/应用私钥JAVA.txt").read())
    signer = PKCS1_v1_5.new(private_key)
    signature = signer.sign(SHA256.new(unsigned_string.encode('utf-8')))
    # 对签名之后的执行base64编码，转换为字符串,并替换字符串中的换行符
    sign_string = encodebytes(signature).decode('utf-8').replace('\n','')
    # 把生成的签名赋值给sign参数，拼接到请求参数中
    result = '&'.join(["{0}={1}".format(k,quote_plus(params[k])) for k in sorted(params)])
    result = result + '&sign=' + quote_plus(sign_string)
    
    gateway = 'https://openapi-sandbox.dl.alipaydev.com/gateway.do'
    pay_url = "{}?{}".format(gateway,result)
    print(pay_url)
"""

# def pay(request):
#     """ 生成订单，并跳转支付 """
#     # 取出放在redis中的数据
#     conn = get_redis_connection()
#     key = 'payment_{}'.format(request.tracer.user.mobile_phone) # 登录用户的手机号码当作key的数据
#     context_string = conn.get(key)
#     # 判断是否超时。如果超时的话就跳转到价格页面
#     if not context_string:
#         return redirect('web/price.html')
#     # 获取的数据context_string是字节数据，所以需要再转换成json格式的数据
#     context = json.loads(context_string.decode('utf-8'))
#     # 获取的数据通过验证后，现在可以在数据库中生成交易记录，状态是待支付的状态
#     # 利用随机字符串函数，生成订单号
#     order_id = uid(request.tracer.user.mobile_phone)
#     total_price = context['total_price']
#     # 在数据库中生成交易记录的数据
#     models.Transaction.objects.create(
#         status = 1,
#         order=order_id,
#         user=request.tracer.user,
#         price_policy_id=context['policy_id'],
#         count=context['number'],
#         price=total_price
#     )
#
#     # 跳转到支付宝支付。1.先生成一个支付的链接。2.跳转到这个链接。
#     """
#         APPID:2021000146632363
#         应用名称:sandbox 默认应用:2088721061481408
#         绑定的商家账号（PID）:2088721061481408
#         支付宝网关地址:https://openapi-sandbox.dl.alipaydev.com/gateway.do
#         websocket服务地址:openchannel-sandbox.dl.alipaydev.com
#         应用公钥：生成支付公钥用
#         应用私钥：对请求支付链接携带的参数进行签名和加密用。如携带的：商品信息，商品数量等等
#         支付公钥：在支付成功后，跳转回调用页面时，对支付宝给我们传的值进行校验
#         安装SDK：pip install alipay-sdk-python
#         手动输入api的参数：
#             参数列表 = ｛
#                 app_id = 2021000146632363,
#                 method:'alipy.trade.page.pay',
#                 format:'JSON',
#                 return_url:"支付成功之后跳转到指定的网址", GET请求
#                 notify_url:"支付成功后同时偷偷的向这个地址发送一个请求",POST请求
#                 charset:'utf-8',
#                 sign_type:'RSA2',
#                 sign:'签名',
#                 timestamp:'2014-07-24 03:07:50',
#                 version:'1.0',
#                 biz_content:{
#                     out_trade_no:'订单号',
#                     product_code:'FAST_INSTANT_TRADE_PAY',
#                     total_amount:11.68,
#                     subject:'订单标题'
#                 }
#             ｝
#
#     """
#
#     # 构造字典
#     params = {
#         'app_id': '2021000146632363',
#         'method': 'alipy.trade.page.pay',
#         'format': 'JSON',
#         'return_url': 'http://172.16.9.237:8007/web/price/',  # 支付成功之后跳转到指定的网址
#         'notify_url': "http://172.16.9.237:8007/web/price/",
#         'charset': 'utf-8',
#         'sign_type': 'RSA2',
#         # 'sign':'签名',
#         'timestamp': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
#         'version': '1.0',
#         'biz_content': json.dumps({
#             'out_trade_no': order_id,
#             'product_code': 'FAST_INSTANT_TRADE_PAY',
#             'total_amount': total_price,
#             'subject': 'tracer payment'
#         }, separators=(',', ':'))
#     }
#     unsigned_string = '&'.join(['{0}={1}'.format(k, params[k]) for k in sorted(params)])
#
#     # 对上面代签名的字符串进行加密签名
#     private_key = RSA.importKey(open("web/static/web/应用私钥JAVA.txt").read())
#     signer = PKCS1_v1_5.new(private_key)
#     signature = signer.sign(SHA256.new(unsigned_string.encode('utf-8')))
#     # 对签名之后的执行base64编码，转换为字符串,并替换字符串中的换行符
#     sign_string = encodebytes(signature).decode('utf-8').replace('\n', '')
#     # 把生成的签名赋值给sign参数，拼接到请求参数中
#     result = '&'.join(["{0}={1}".format(k, quote_plus(params[k])) for k in sorted(params)])
#     result = result + '&sign=' + quote_plus(sign_string)
#
#     gateway = 'https://openapi-sandbox.dl.alipaydev.com/gateway.do'
#     alipay_url = "{}?{}".format(gateway, result)
#     return redirect(alipay_url)

class AliPay(object):
    """ 支付宝支付接口"""
    def __init__(self,appid,app_notify_url,app_private_key_path,alipay_public_key_path,return_url):
        self.appid = appid
        self.app_notify_url = app_notify_url
        self.app_private_key_path = app_private_key_path
        self.alipay_public_key_path = alipay_public_key_path
        self.app_private_key = None
        self.return_url = return_url
        with open(self.app_private_key_path) as fp:
            self.app_private_key = RSA.importKey(fp.read())
        with open(self.alipay_public_key_path) as fp:
            self.alipay_public_key = RSA.importKey(fp.read())
    def direct_pay(self,subject,out_trade_no,total_amount,return_url=None,**kwargs):
        biz_content = {
            "subject":subject,
            "out_trade_no":out_trade_no,
            "total_amount":total_amount,
            "product_code":"FAST_INSTANT_TRADE_PAY",
        }
        biz_content.update(kwargs)
        data = self.build_body("alipay.trade.page.pay",biz_content,self.return_url)
        return self.sign_data(data)
    def build_body(self,method,biz_content,return_url=None):
        data = {
            "app_id":self.appid,
            "method":method,
            "charset":'utf-8',
            'sign_type': 'RSA2',
            # 'sign':'签名',
            'timestamp': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
            'version': '1.0',
            'biz_content':biz_content
        }
        if return_url is not None:
            data['notify_url'] = self.app_notify_url
            data['return_url'] = self.return_url
        return data
    def sign_data(self,data):
        data.pop('sign',None)
        # 排序后的字符串
        unsigned_items = self.ordered_data(data)
        unsigned_string = "&".join("{0}={1}".format(k,v) for k,v in unsigned_items)
        sign = self.sign(unsigned_string.encode('utf-8'))
        quote_string = "&".join("{0}={1}".format(k,quote_plus(v)) for k,v in unsigned_items)
        # 获取最终订单信息的字符串
        signed_string = quote_string + "&sign=" + quote_plus(sign)
        return signed_string
    def ordered_data(self,data):
        complex_keys = []
        for key,value in data.items():
            if isinstance(value,dict):
                complex_keys.append(key)
        # 将字典类型的数据dump出来
        for key in complex_keys:
            data[key] = json.dumps(data[key],separators=(',',':'))
        return sorted([(k,v) for k,v in data.items()])

    def sign(self,unsigned_string):
        # 开始计算签名
        key = self.app_private_key
        signer = PKCS1_v1_5.new(key)
        signature = signer.sign(SHA256.new(unsigned_string))
        # base64编码，转换为unicode，并移除回车换行符
        sign = encodebytes(signature).decode('utf8').replace('\n','')
        return sign
    def verify(self,raw_content,signature):
        # 开始计算签名
        key = self.alipay_public_key
        signer = PKCS1_v1_5.new(key)
        digest = SHA256.new()
        digest.update(raw_content.encode('utf8'))
        if signer.verify(digest,decodebytes(signature.encode('utf8'))):
            return True
        return False










